package hawmeterclient;

// url ist case sensive
// Ausfuehren:
// C:\Users\Home\workspace\HAWMeterClient>java -cp build/ hawmeterclient/HAWMeterClientServer

import hawmeterclientproxy.HAWMeterClientService;
import hawmeterproxy.HAWMeteringWebservice;
import hawmeterproxy.HAWMeteringWebserviceService;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;
import javax.xml.ws.WebServiceException;

public class HAWMeterClientServer{
	
	
	public enum Mode {
	    CLIENT, KOORDINATOR 
	}
	final static int MAX_ANZEIGE = 4;
	
		
	static HAWMeterClient client;
	static String clientUrl, hawurl;
	static HAWMeteringWebservice[] metering = new HAWMeteringWebservice[MAX_ANZEIGE];
	static hawmeterclientproxy.HAWMeterClient meterClient, meterKoor;
	
	static Mode mode=Mode.CLIENT;
	static Endpoint endpoint;
	static String koor=null;
	static URL baseUrl = HAWMeterClientService.class.getResource(".");
	static String[] list = new String[4];
	static Semaphore warten=new Semaphore(0);
    private static int timeout=2500;	
	
	
	public static void main(String[] args) {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int input = 0;
		boolean running=true;
		
		
		list[0]="";
		list[1]="";
		list[2]="";
		list[3]="";
		
		try{
			create();
			menu();
			while(running){
				
					/* Get Choice */
					String is = in.readLine();
					/* Print Menu if ask for help */
					if(is.equals("Help") ||is.equals("help")){
						menu();
						input = 0;
					}else
						input = Integer.parseInt(is);
				 
				switch(input)
						{
				/* Start Functionality */
					case 1 : startKoor(); 		break; // Startet Client als Koordinator 
					case 2 : startClient();		break; // Startet Client URL eines beliebigen Clients muss �bergeben werden
					case 3 : register();		break; // Versucht sich bei einer Anzeige zu registieren
					case 4 : run();				break; // 
					//case 8 : running = false;   break; // Beendet den client
					default : 	break;
				}
				menu();
			}
		} catch (IOException e){
			System.err.println(e.getMessage());
		} catch(Exception E){
			E.printStackTrace();
			System.out.println("Exiting");
			System.exit(0);
		}
		             
	    endpoint.stop(); 
	}
	
	private static void run() {
		
		while(true){
			
				while(mode==Mode.KOORDINATOR){
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					triggerClients();
					
					//System.out.println("send trigger:" );
				}
			try {
				if(!warten.tryAcquire(timeout, TimeUnit.MILLISECONDS)){
					abmelden(koor);
					wahlen();
				}
				System.out.println("fertig");
					
			} catch (InterruptedException e) {
				System.err.println("ERROR: " + e);
				e.printStackTrace(System.out);
			}
		}
	}
	
	

	private static void create() {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		try {
			System.out.println("URL des Client angeben (Format: <host>:<port>/<name>) :");
			clientUrl = "http://" + in.readLine();
			client = new HAWMeterClient();
			endpoint = Endpoint.publish(clientUrl, client);
		    System.out.println("Done: " + clientUrl );
		    
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private static void menu(){
		/* Print Menu */
		System.out.println("\nMoeglichkeiten : \n" +
				   "[1] Client als Koordinator \n" +
				   "[2] Client anmelden bei Client-URL \n" +
				   "[3] Client an Anzeigen registieren \n" +
				   //"[4] Client starten\n\n" +
				   "Bitte Auswahl eingeben : ");
	}
	
	private static void startKoor() {
		
		try {
			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("Rechnername des HAW Metering angeben (Format: <host>:");
			hawurl = in.readLine();
		} catch (Exception e) {
			e.printStackTrace();
		}
		koor=clientUrl;
		setKoor();
		register();
		run();
	}
	
	private static void register() {
		URL url = null;
		URL baseUrl = HAWMeteringWebserviceService.class.getResource(".");
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		boolean ready=false;

		try {
			do{
				System.out.println("An welchen Anzeigen versuchen zu registieren: {no,nw,so,sw}");
				String is = in.readLine();
				if(is.equals("no")==true || is.equals("nw")==true || is.equals("so")==true || is.equals("sw")==true ){
					//den koordinator fragen ob anzeige frei
					if(meterKoor.anmelden(is, clientUrl)){
						url = new URL(baseUrl, "http://" + hawurl + ":9999/hawmetering/" + is + "?WSDL");
						HAWMeteringWebserviceService service = new HAWMeteringWebserviceService(url, new QName("http://hawmetering/", "HAWMeteringWebserviceService"));
						metering[getAnzeige(is)] = service.getHAWMeteringWebservicePort();
						System.out.println("Done. Angemeldet an: " + is);
					} else {
						System.out.println("Gewaehlte Anzeige belegt");
					}
				} else {
					System.out.println("Falsche Eingabe: " + is);
				}
				System.out.println("An weiteren Anzeigen registieren: {j/n}");
				is = in.readLine();
				if(is.equals("j")==true){
					ready=false;
				}else if (is.equals("n")==true){
					ready=true;
					System.out.println("Client wird gestartet");
					run();
				} else {
					System.out.println("Falsche Eingabe: " + is);
				}
			}while(ready==false);	
			
		} catch (IOException e) {
			e.printStackTrace();
		} 
		
	}

	private static void startClient() {
		mode=Mode.CLIENT;
		URL url = null;
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		try {
			System.out.println("URL eines beliebigen Client angeben (Format: <host>:<port>/<name>) :");
			String is = "http://" + in.readLine();
			url = new URL(baseUrl, is + "?WSDL");
			HAWMeterClientService service = new HAWMeterClientService(url, new QName("http://hawmeterclient/", "HAWMeterClientService"));
			meterClient = service.getHAWMeterClientPort();
			koor = meterClient.getKoor();
			hawurl = meterClient.getHawurl();
			System.out.println("Done " + koor);
			setKoor();		
		} catch (IOException e) {
			e.printStackTrace();
		}
	
	}
	private static void triggerClients(){
		String[] sendurls = new String[4];
		sendurls[0] = "";
		sendurls[1] = "";
		sendurls[2] = "";
		sendurls[3] = "";
		hawmeterclientproxy.HAWMeterClient triggerClient=null;
		
			//System.out.println(list[0]+" : " +list[1]+" : "+list[2]+" : "+list[3]);
			
			for(int i=0; i < MAX_ANZEIGE; i++){
				if (list[i].equals(""))continue;
				for(int j=0;j<=3; j++){
					if(sendurls[j].equals(list[i])){
						//System.out.println("vergleich list" +j+ sendurls[j]);
						break;
					} else {
						sendurls[i]=list[i];
					}
				}
			}
			//System.out.println(sendurls.length);
			for(int i=0; i < sendurls.length; i++){
				if (sendurls[i].equals(""))continue;
				try {
					triggerClient = getPort(sendurls[i]);
					triggerClient.trigger(list[0], list[1], list[2], list[3], hawurl);
				} catch (NEException e) {
					System.out.println("NNE in trigger");
					break;
				} catch (NullPointerException e) {
					
				}
			}
	}
	private static void setKoor() {
		
		URL url;
		
		if(koor.equals(clientUrl)){
			mode=Mode.KOORDINATOR;
		}
		try {
			url = new URL(baseUrl, koor + "?WSDL");
			HAWMeterClientService service = new HAWMeterClientService(url, new QName("http://hawmeterclient/", "HAWMeterClientService"));
			meterKoor = service.getHAWMeterClientPort();
			
			
			System.out.println("New Koor: " + koor);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (WebServiceException e){
			System.out.println("keine Verbindung zum Koor: " + koor);
			abmelden(koor);
			wahlen();
		}
	}

	private static int getAnzeige(String is){
		int i=-1;
		if(is.equals("nw")) i=0;
		if(is.equals("no")) i=1;
		if(is.equals("sw")) i=2;
		if(is.equals("so")) i=3;
		
		return i;
		
	}
	
	private static hawmeterclientproxy.HAWMeterClient getPort (String is) throws NEException{
		URL url = null;
		hawmeterclientproxy.HAWMeterClient tmp=null;
		try {
			url = new URL(baseUrl, is + "?WSDL");
			HAWMeterClientService service = new HAWMeterClientService(url, new QName("http://hawmeterclient/", "HAWMeterClientService"));
			tmp = service.getHAWMeterClientPort();
		
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (WebServiceException e){
			System.out.println("Verbindung zu " + is + " verloren");
			abmelden(is);
			
		}
		
		return tmp;
		
		
		
	}

	private static void abmelden(String is) {
		
		for(int i=0; i < MAX_ANZEIGE; i++){
			if(list[i].equals(is)){
				list[i]="";
			}
		}	
	}
	
	private static void wahlen() {

		koor="";
		
		for(int i=0; i < MAX_ANZEIGE; i++){
			if(list[i].compareTo(koor)>0){
				koor=list[i];
			}
		}
		System.out.println("neuer Koor: " + koor );
		
		setKoor();
	}
	
}